package com.gitee.wsl.ext.okio.source

import com.gitee.wsl.ext.okio.base.CallState
import kotlinx.coroutines.channels.SendChannel
import okio.Buffer
import okio.ForwardingSource
import okio.Source


/**
 * A [Source] for counting the number of bytes downloaded.
 */
class CountingSource(
    delegate: Source,
    startOffset: Long,
    private val contentLength: Long,
    private val channel: SendChannel<CallState.Downloading>
) : ForwardingSource(delegate) {

    var bytesDownloaded: Long = startOffset

    override fun read(sink: Buffer, byteCount: Long): Long =
        super.read(sink, byteCount).also { bytesRead ->
            if (bytesRead > 0) {
                bytesDownloaded += bytesRead
                emitDownloadProgress()
            }
        }

    private fun emitDownloadProgress() {
        // Since the channel is CONFLATED, `trySend()` will always succeed unless the channel is
        // cancelled. If the channel is cancelled, it means that the HTTP call is cancelled, so
        // the cancellation will be notified as an IOException on `source.read()`.
        // Therefore, the result of `trySend()` can be ignored here.
        channel.trySend(CallState.Downloading(bytesDownloaded, contentLength))
    }
}
